package org.happycomp.radiog;

import static org.happycomp.radiog.utils.GUIConditions.*;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.part.ViewPart;
import org.happycomp.radio.ProcessStates;
import org.happycomp.radio.Station;
import org.happycomp.radio.StopDownloadCondition;
import org.happycomp.radio.StoreState;
import org.happycomp.radio.StoreStateException;
import org.happycomp.radio.downloader.DownloadingItem;
import org.happycomp.radio.downloader.impl.IvalidPlaylistContentException;
import org.happycomp.radio.io.IOUtils;
import org.happycomp.radio.planner.PlannedItem;
import org.happycomp.radio.planner.Planner;
import org.happycomp.radio.scheduler.SchedulerListener;
import org.happycomp.radiog.core.StopTimeCondition;
import org.happycomp.radiog.dialog.common.DateDialog;
import org.happycomp.radiog.dialog.convert.ConvertSelectionDialog;
import org.happycomp.radiog.dialog.plan.PlanNewDialog;
import org.happycomp.radiog.encoding.EncodeMonitor;
import org.happycomp.radiog.encoding.EncodeProcessThread;
import org.happycomp.radiog.utils.GUIConditions;


public class ModifyButtonsView extends ViewPart implements ISelectionListener, SchedulerListener {

	public static final Logger LOGGER = Logger.getLogger(ModifyButtonsView.class.getName());
	
	private IStructuredSelection selectedItems;

	private Button addButton;
	private Button stopButton;
	private Button removeButton;
	private Button convertButton;
	
	private Button storeWorkButton;
	private Button restoreWorkButton;
	
	@Override
	public void createPartControl(Composite parent) {
		SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
		modifyButtonsPanel(sashForm);
		storeAndRestoreWorkPanel(sashForm);
		
		Activator.getDefault().getRadioScheduler().addSchedulerListener(this);
	}

	
	private void storeAndRestoreWorkPanel(SashForm sashForm) {
		Composite composite = new Composite(sashForm, SWT.NONE);
		GridLayout layout = new GridLayout(); {
			layout.numColumns = 1;
			layout.marginBottom = 10;
			layout.marginLeft = 10;
			layout.marginRight = 10;
		}
		composite.setLayout(layout);
		
		storeWorkButton = new Button(composite, SWT.PUSH);
		storeWorkButton.setText("Uloz stav");
		storeWorkButton.setEnabled(false);
		storeWorkButton.setLayoutData(gridDataForButtons());	
		storeWorkButton.addSelectionListener(new SelectionListener() {
			
			@Override
			public void widgetSelected(SelectionEvent e) {
				System.out.println("Iterating through downloading items ... ");
				DownloadingItem[] downloadingItems = Activator.getDefault().getRadioScheduler().getDownloader().getDownloadingItems();
				storeState(downloadingItems);
			}
			
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				// TODO Auto-generated method stub
				
			}
		});

		restoreWorkButton = new Button(composite, SWT.PUSH);
		restoreWorkButton.setLayoutData(gridDataForButtons());
		restoreWorkButton.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				try {
					DownloadingItem[] itms = Activator.getDefault().getStoreInfos().getDownloadingItems();
					Activator.getDefault().getRadioScheduler().getDownloader().setDownloadingItems(itms);
					new SyncExecTemplate(getSite(),new Runnable() {
						
						@Override
						public void run() {
							Activator.getDefault().getRadioScheduler().fireRefreshIterval();
						}
					}).execute();
				} catch (StoreStateException e1) {
					MessageDialog.openError(getSite().getShell(), "Chyba pri ukladani stavu", "Nemuzu ulozit stav "+e1.getMessage());
				}

			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				// TODO Auto-generated method stub
				
			}
			
		});
		
		restoreWorkButton.setText("Nahraj stav");
		restoreWorkButton.setEnabled(true);
	}
	
	private void modifyButtonsPanel(SashForm sashForm) {
		Composite composite = new Composite(sashForm, SWT.NONE);
		GridLayout layout = new GridLayout(); {
			layout.numColumns = 1;
			layout.marginBottom = 10;
			layout.marginLeft = 10;
			layout.marginRight = 10;
		}
		composite.setLayout(layout);
		
		
		addButton = new Button(composite, SWT.PUSH); {
			addButton.addSelectionListener(new SelectionListener() {
				
				@Override
				public void widgetSelected(SelectionEvent e) {
					Button but = (Button) e.getSource();
					PlanNewDialog pd = new PlanNewDialog(but.getShell());
					if (IDialogConstants.OK_ID == pd.open()) {
						Date startTime = pd.getStartTime();
						Date stopTime = pd.getStopTime();
						boolean shutdown = pd.isShutdown();
						if (stopTime.before(startTime)) {
							boolean ano = LocalizedDialog.openQuestion(getSite().getShell(), "Nahravani na dalsi den", "Zacatek nahravani je planovan pozdeji nez jeho konec. Prejete si zmenit datum ukonceni nahravani?");
							if (ano) {
								DateDialog date = new DateDialog(getSite().getShell());
								if (date.open() == IDialogConstants.OK_ID) {
									int year = date.getYear();
									int month = date.getMonth();
									int day = date.getDay();
									
									int stopTimeHours = pd.getStopTimeHours();
									int stopTimeMinutes = pd.getStopTimeMinutes();
									

									Calendar cal = Calendar.getInstance();
									cal.set(Calendar.YEAR,year);
									cal.set(Calendar.MONTH, month);
									cal.set(Calendar.DAY_OF_MONTH,day);
									
									cal.set(Calendar.MINUTE, stopTimeMinutes);
									cal.set(Calendar.HOUR_OF_DAY, stopTimeHours);
									
									stopTime = cal.getTime();
								}
							}
						}
						Station station = pd.getStation();
						Activator.getDefault().getRadioScheduler().getPlanner().plan(station, new StopTimeCondition(stopTime), pd.getTitle(), startTime);
						if (!Activator.getDefault().getRadioScheduler().isStarted()) {
							Activator.getDefault().getRadioScheduler().start();
						}
						Activator.getDefault().getRadioScheduler().fireRefreshIterval();
						if (shutdown) {
							Calendar cal = Calendar.getInstance();
							cal.setTime(stopTime);
							cal.add(Calendar.SECOND, 20);
							Activator.getDefault().getRadioScheduler().setShutdownSystemDate(cal.getTime());
						}
					}
					
				}
				
				@Override
				public void widgetDefaultSelected(SelectionEvent e) {
					// TODO Auto-generated method stub
					
				}
			});
		}
		
		addButton.setText("Nove nahravani");
		addButton.setLayoutData(gridDataForButtons());

		stopButton = new Button(composite, SWT.PUSH);
		stopButton.setText("Zastav nahravani");
		stopButton.setLayoutData(gridDataForButtons());
		stopButton.addSelectionListener(new SelectionListener() {
			
			@Override
			public void widgetSelected(SelectionEvent e) {
				DownloadingItem item = getItem(selectedItems, DownloadingItem.class);
				LOGGER.info("manual stop on condition '"+item.getStopDownloadCondition()+"'");
				item.geStopDownloadingCondition().manualStop();


				MessageDialog.openInformation(getSite().getShell(), "Information", "Zastaveni trva 2-3s");

				new SyncExecTemplate(getSite(),new Runnable() {
					
					@Override
					public void run() {
						LOGGER.info("refreshing interval ...");
						Activator.getDefault().getRadioScheduler().fireRefreshIterval();
					}
				}).execute();
			}
			
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});

		removeButton = new Button(composite, SWT.PUSH);
		removeButton.setText("Odeber");
		removeButton.setLayoutData(gridDataForButtons());
		removeButton.setEnabled(false);
		removeButton.addSelectionListener(new SelectionListener() {
			
			@Override
			public void widgetSelected(SelectionEvent e) {
//				Planner planner = Activator.getDefault().getRadioScheduler().getPlanner();
				boolean b = LocalizedDialog.openQuestion(getSite().getShell(), "Smazat soubr", "Opravdu smazat soubor ?");
				if (b) {
					PlannedItem pitem = getItem(selectedItems, PlannedItem.class);
					if (pitem != null) {
						Activator.getDefault().getRadioScheduler().getPlanner().removePlannedItem(pitem);
						
						
						selectedItems = null;
						changeButtonsEnabled();

						IViewReference[] viewReferences = getSite().getWorkbenchWindow().getActivePage().getViewReferences();
						for (IViewReference ref : viewReferences) {
							IViewPart view = ref.getView(false);
							if (view instanceof ContentView) {
								ContentView cv = (ContentView) view;
								cv.refresh();
							}
						}
					} else {
						DownloadingItem ditem = getItem(selectedItems, DownloadingItem.class);
						try {
							if (ditem.isPersistedItem()) {
								StoreState storeStates = Activator.getDefault().getStoreInfos();
								storeStates.deleteDownloadingItem(ditem);
							}
							boolean delete = ditem.getFile().delete();
							if (delete) {
								Activator.getDefault().getRadioScheduler().getDownloader().removeDownloadingItem(ditem);

								selectedItems = null;
								changeButtonsEnabled();
								
								IViewReference[] viewReferences = getSite().getWorkbenchWindow().getActivePage().getViewReferences();
								for (IViewReference ref : viewReferences) {
									IViewPart view = ref.getView(false);
									if (view instanceof ContentView) {
										ContentView cv = (ContentView) view;
										cv.refresh();
									}
								}
								
							} else {
								MessageDialog.openError(getSite().getShell(), "Chyba pri mazani souboru", "Nemuzu smazat soubor :"+ditem.getFile().getAbsolutePath());
							}
						} catch (StoreStateException e1) {
							MessageDialog.openError(getSite().getShell(), "Chyba pri mazani souboru", e1.getMessage());
						}
					}
				}
			}
			
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				// TODO Auto-generated method stub
				
			}
		});
		
		convertButton = new Button(composite, SWT.PUSH);
		convertButton.setText("Konvertuj ");
		convertButton.setLayoutData(gridDataForButtons());
		convertButton.setEnabled(false);
		convertButton.addSelectionListener(new SelectionListener() {
			
			@Override
			public void widgetSelected(SelectionEvent e) {
				
				if (checkCommand()) {
					final  DownloadingItem item = getItem(selectedItems, DownloadingItem.class);
					ConvertSelectionDialog selDial = new ConvertSelectionDialog(getSite().getShell());
					if (IDialogConstants.OK_ID == selDial.open()) {
						boolean generateMp3Flag = selDial.getGenerateMp3Flag();
						boolean deleteWavFileFlag = selDial.getDeleteWavFileFlag();
						File file = openFile(generateMp3Flag, deleteWavFileFlag);
						File mp3File = null;
						File wavFile = null;

						file = fillExtension(generateMp3Flag, file);
						if (generateMp3Flag) {
							mp3File = file;
							String fileName = file.getName().toLowerCase();
							wavFile = new File(mp3File.getParentFile(), fileName.substring(0,fileName.length()-".mp3".length())+".wav");
						} else {
							wavFile = file;
						}
						try {
							File randomFolder = randomFolder();
							boolean mkdirs = randomFolder.mkdirs();

							if (!mkdirs) {
								MessageDialog.openError(getSite().getShell(),"Chyba pri vytvareni adresare", "nemohu vytvorit adresar "+ randomFolder.getAbsolutePath());
							} else {
								EncodeProcessThread thread = new EncodeProcessThread(item.getFile(), item.getPreviousFiles(), wavFile, mp3File, deleteWavFileFlag, null, randomFolder);
								thread.start();
								item.setState(ProcessStates.PROCESSED);
							}

						} catch (IOException e1) {
							MessageDialog.openError(getSite().getShell(), "Error in starting command", "Nemuzu spustit prikaz !");
						}
					}
				}
			}

			
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});
		
		this.stopButton.setEnabled(false);

		
		getSite().getPage().addSelectionListener(this);
	}

	
	
	@Override
	public void exceptionOccured(final Throwable arg0) {
		// spatny descriptor radia
		if (arg0 instanceof IvalidPlaylistContentException) {
			new SyncExecTemplate(getSite(), new Runnable() {
				@Override
				public void run() {
					IvalidPlaylistContentException plex = (IvalidPlaylistContentException) arg0;
					MessageDialog.openError(getSite().getShell(), "Spatny playlist radia", "Obsah adresy:"+plex.getContent());
				}
			}).execute();
			
		// genericka vyjimka
		} else {
			new SyncExecTemplate(getSite(), new Runnable() {
				@Override
				public void run() {
					StringWriter stringWriter = new StringWriter();
					arg0.printStackTrace(new PrintWriter(stringWriter));
					MessageDialog.openError(getSite().getShell(), arg0.getClass().getName(), stringWriter.toString());
				}
			}).execute();
		}
	}


	@Override
	public void refreshInterval() {
		
		new SyncExecTemplate(getSite(), new Runnable() {
			@Override
			public void run() {
				PlannedItem justPopped = Activator.getDefault().getRadioScheduler().getPlanner().getJustPopped();
				PlannedItem[] plannedItems = Activator.getDefault().getRadioScheduler().getPlanner().getPlannedItems();
				DownloadingItem[] downloadingItems = Activator.getDefault().getRadioScheduler().getDownloader().getDownloadingItems();
				storeWorkButton.setEnabled(plannedItems.length == 0 && downloadingItems.length > 0 && (areItemsInStates(downloadingItems, ProcessStates.STOPPED, ProcessStates.KILLED, ProcessStates.PROCESSED)));
				restoreWorkButton.setEnabled(plannedItems.length==0 && downloadingItems.length == 0 && justPopped == null);
			}
		}).execute();
	}


	@Override
	public void startDownloading() {
	}


	@Override
	public void stopDownloading(DownloadingItem arg0) {
	}


	protected File fillExtension(boolean generateMp3Flag, File file) {
		String extesion = generateMp3Flag ? ".mp3" : ".wav";
		if (file.getName().toLowerCase().endsWith(extesion)) {
			return file;
		} else {
			return new File(file.getAbsolutePath()+extesion);
		}
	}

	private GridData gridDataForButtons() {
		GridData data = new GridData(); {
			data.horizontalAlignment = SWT.FILL;
			data.verticalAlignment = SWT.CENTER;
			data.grabExcessHorizontalSpace = true;
			data.verticalSpan = 5;
			data.horizontalSpan = 5;
		}
		return data;
	}

	


	
	@Override
	public void setFocus() {
	}

	@Override
	public void selectionChanged(IWorkbenchPart part, ISelection selection) {
		if (part instanceof ContentView) {
			this.selectedItems = (IStructuredSelection) selection;
			this.changeButtonsEnabled();
		}
	}
	
	public void changeButtonsEnabled() {
		if ((this.selectedItems == null) || (this.selectedItems.isEmpty())) {
			this.stopButton.setEnabled(false);
			this.removeButton.setEnabled(false);
			this.convertButton.setEnabled(false);
		} else {
			final DownloadingItem downloadingSelected = getItem(this.selectedItems, DownloadingItem.class);
			final PlannedItem plannedSelected = getItem(this.selectedItems, PlannedItem.class); 
			getSite().getShell().getDisplay().asyncExec(new Runnable() {
				@Override
				public void run() {
					changeFlagForModifyButtons(downloadingSelected, plannedSelected);
				}
			});
		}
	}

	private void changeFlagForModifyButtons(DownloadingItem ditem, PlannedItem pitem) {
		this.stopButton.setEnabled(ditem != null && isDownloading(ditem));
		this.removeButton.setEnabled((ditem != null && isDownloaded(ditem)) || pitem != null);
		this.convertButton.setEnabled(ditem != null && isDownloaded(ditem));
	}
	
	private boolean isDownloaded(DownloadingItem ditem) {
		return ditem.getProcessState() == ProcessStates.STOPPED || 
				ditem.getProcessState() == ProcessStates.PROCESSED;
	}

	private boolean isDownloading(DownloadingItem ditem) {
		return ditem.getProcessState() == ProcessStates.DOWNLOADING;
	}
	
	public static <T> T getItem(IStructuredSelection selection, Class<T> clz) {
		if ((selection != null) && (!selection.isEmpty())) {
			Object[] array = selection.toArray();
			for (Object object : array) {
				if (object.getClass().equals(clz)) {
					return (T) object;
				}
			}
			return null;
		} else {
			return null;
		}
	}
	
	
	private File openFile(boolean generateMp3Flag, boolean deleteWavFileFlag) {
		FileDialog fd = new FileDialog(getSite().getShell(), SWT.OPEN);
	    fd.setText("Open");
	    String[] filterExt = new String[]{ "*.wav" };
	    if (generateMp3Flag) {
	    	filterExt = new String[] {"*.mp3"};
	    }
	    fd.setFilterExtensions(filterExt);
	    String openedPath = fd.open();
		return openedPath != null ? new File(openedPath) : null;
	}
	
	private boolean checkCommand() {
		try {
			Activator.getDefault().getCommandsMap();
			return true;
		} catch (IOException ex) {
			LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
			MessageDialog.openError(getSite().getShell(),ex.getClass().getName(), ex.getMessage());
			return false;
		}
	}

	private File randomFolder() {
		UUID randomUUID = UUID.randomUUID();
		String uuidString = randomUUID.toString();
		File randomFolder = new File(Activator.baseDir()+File.separator+uuidString);
		return randomFolder;
	}

	private void storeState(DownloadingItem[] downloadingItems) {
		for (DownloadingItem ditm : downloadingItems) {
			try {
				Activator.getDefault().getStoreInfos().storeDownloadingItem(ditm);
			} catch (StoreStateException e1) {
				e1.printStackTrace();
			}
		}
	}



	static class LocalizedDialog extends MessageDialog {

		private LocalizedDialog(Shell parentShell, String dialogTitle,
				Image dialogTitleImage, String dialogMessage,
				int dialogImageType, String[] dialogButtonLabels,
				int defaultIndex) {
			super(parentShell, dialogTitle, dialogTitleImage, dialogMessage,
					dialogImageType, dialogButtonLabels, defaultIndex);
		}
		
		
	    public static boolean openQuestion(Shell parent, String title,
	            String message) {
//	        return open(QUESTION, parent, title, message, SWT.NONE);
			LocalizedDialog dialog = new LocalizedDialog(parent, title, null, message,
					QUESTION, new String[]{"Ano","Ne"}, 0);
			int style = SWT.NONE & SWT.SHEET;
			dialog.setShellStyle(dialog.getShellStyle() | style);
			return dialog.open() == 0;
	    }

		
	}



	@Override
	public void shutDown() {
	}
	
	
}
